#pragma once

namespace png8crop
{

	enum value_type
	{
		vt_na,
		vt_dword,
		vt_word,
		vt_byte
	};

	struct const_info
	{
		const _TCHAR * key;
		const void* value;
		value_type type;

		const_info()
			:key(NULL),
			value(NULL)
		{
		}

		const_info(const _TCHAR * indentifier, const void * value, value_type type)
			: key(indentifier),
			value(value),
			type(type)
		{
		}
	};

	typedef void (*variable_callback) (const void * var, const void * the_param);

	struct diam_info
	{
		size_t bytes;
		int scales;
	};

	struct diam_list
	{
		int diam_count;
		diam_info * diams;
	};


	struct variable_info
	{
		const _TCHAR * key;
		void * value;
		value_type type;
		diam_list * diamlist;
		variable_callback callback;
		void * cbparam;

		variable_info()
			:key(NULL),
			value(NULL),
			diamlist(NULL),
			callback(NULL),
			cbparam(NULL)
		{
		}

		variable_info(const _TCHAR * indentifier, void * ptr, value_type type, diam_list* diams, variable_callback callback, void * cbparam)
			: key(indentifier),
			value(ptr),
			type(type),
			diamlist(diams),
			callback(callback),
			cbparam(cbparam)
		{
		}
	};

	using namespace std;

	class mnu_parser
	{
	private:
		std::map<_tstring, const_info> constants;
		std::map<_tstring, variable_info> variables;
		std::map<value_type, size_t> typedefs;

		const _TCHAR* current;

	public:
		mnu_parser(void);
		~mnu_parser(void);
		void register_const(const _TCHAR * indentifier, const void * value, value_type type);
		void register_type(value_type type, size_t unit);
		void register_variable(const _TCHAR * indentifier, void * ptr, value_type type, diam_list* diams, variable_callback callback, void * cbparam);

		void parse_line(const _TCHAR* line);

	private:
		void parse_set();
		void parse_remarks();
		void parse_const(void* addr, value_type expected_type);

		bool is_idnstart(_TCHAR val)
		{
			return val && (isalpha(val) || val == _T(':') || val == _T('_'));
		}

		bool is_idnchar(_TCHAR val)
		{
			return val && (isalnum(val) || val == _T(':') || val == _T('_'));
		}

		const _TCHAR * skip_idnchar()
		{
			const _TCHAR * ret = current;
			while(is_idnchar(*ret)) ret++;

			return ret;
		}

		const _TCHAR *  skip_spaces()
		{
			const _TCHAR * ret = current;
			while((*ret) && isspace(*ret)) ret++;

			return ret;
		}

	};

}